Merge main into stable#3589
Conversation
- Added validation for the MCP_PRESET environment variable in `server.ts` to ensure only supported presets are accepted at startup, preventing silent misconfigurations. - Introduced a new preset registry in `presets.ts`, allowing for the management of LLM tool presets, with the initial implementation supporting only the 'legacy' preset. - Updated the Node SDK to expose preset-related functions (`getPreset`, `listPresets`, `DEFAULT_PRESET`) for easier access to preset information. - Created tests for preset validation and registry functionality, ensuring that unknown presets trigger appropriate errors and that the legacy preset behaves as expected. - Added corresponding Python SDK support for the preset registry, mirroring the Node implementation for consistency across languages.
A searchable "Smart tags" palette in the contract-templates sidebar. Clicking a
tag inserts it as an inline content control at the caret, and the inserted field
paints with the SAME token look (--tag-* / .smart-tag) as the palette chip - so
the sidebar tag and the in-editor field read as one object. This is the core
custom-SDT story: turn off built-in chrome, style the painted wrapper, author
fields from your own UI.
Insert path (verified): ui.selection.capture() -> bridge the TextTarget to a
collapsed SelectionTarget -> editor.doc.create.contentControl({ at, content,
tag }) -> ui.contentControls.focus(). Adds a behavior test proving collapsed-
caret insertion works (no API gap) and a demo acceptance test for chip -> field.
- Smart tags get a deliberate amber identity (one --tag-* token set drives both the palette chip and the painted in-editor field, so they look identical). - Two-way loop: clicking a smart-field token in the document highlights its sidebar chip (content-control:click); cleared on blur (active-change). - README reframed around the custom content-control UI story (chrome:'none' + host-owned field look + smart-tags authoring), with the new flow documented. - Adds a demo test for the click-token -> highlight-chip sync.
…field chip - Remove the floating field chip (sd-field-chip): redundant now fields are styled inline, and it clashed with the amber palette. Drops field-chip.ts and the chip-anchor test (the chip was the only getRect/viewport.observe consumer). - Inline and block fields now share one amber token language: inline as a token pill, block clauses as a quiet left-rail card (a region, not a token). - Kill the jitter: under chrome:'none' SuperDoc resets the SDT border/fill on hover (:hover / .sdt-group-hover) and select (.ProseMirror-selectednode) so consumers own the look; without re-asserting, the box shifted ~2px and lost the amber. We re-assert both states for inline and block to hold the exact box and keep a controlled amber fill. The !important is ours, to win over the reset without coupling to SuperDoc's selector specificity -- a custom-UI styling rough edge (no first-class per-control hook yet) worth a follow-up. - Size the sidebar chips to match the in-editor pills. - Add regression tests asserting the inline pill and block clause boxes stay constant across hover/select (no jitter).
feat: add layered style export
…SDTs
Reframe the contract-templates demo as a building-block library on a locked
template surface, driven entirely through the public superdoc/ui + editor.doc.*
API with chrome:'none'. This shows the legal-tech workflow: assemble a contract
from governed, reusable Word content controls whose variables stay consistent.
- Enable the formatting toolbar and center the editor. Fold Clauses into a
Template tab; the sidebar is now Template (build) + Values (fill).
- Template tab is a catalog: smart-field chips and clause cards (each with
category / jurisdiction / version and a "used N times" count, plus a
library-only Indemnification clause). Drag or click to insert; a field goes
inline at the caret, a clause snaps to a block boundary. Inserts resolve the
drop point with ui.viewport.positionAt.
- Every control is contentLocked, so it can't be edited by typing. Fields show
their name token (e.g. DISCLOSING_PARTY) as a placeholder. Values are filled
only through the Values form, which broadcasts to every occurrence - including
ones nested in a locked clause (the write briefly unlocks clauses, since a
clause's content lock otherwise silently vetoes nested writes).
- Clauses are assembled from structured parts (prose + {field} slots): inserting
one wraps each slot as a nested, locked inline smart field, so an inserted
Permitted Use carries real Receiving party / Purpose fields like the seeded one.
- Remove the clause version review/replace lifecycle (out of scope here; it's a
separate clause-lifecycle demo). Drop the floating field chip earlier in the arc.
- Rewrite the README and file header to the library model; add tests for locking,
nested-clause broadcast, clause insert, and inserted-clause field nesting.
Three review findings from PR 3541:
1. Restore structured ToolCatalog.tools type. The refactor narrowed the
public catalog row to `unknown[]`, breaking TS consumers that read
tools[i].toolName etc. Move ToolCatalogEntry + ToolCatalogOperation
into presets.ts as public types and tighten the catalog signature.
2. Fail fast on malformed provider bundles. Node and Python preset
loaders previously coerced a missing or non-array `tools` field to
`[]`, hiding broken codegen output behind a silently empty tool
surface. Restore the pre-presets TOOLS_ASSET_INVALID throw at the
preset boundary.
3. Cross-lang parity for empty-string presets. Python choose_tools
treated `{'preset': ''}` as legacy via `or DEFAULT_PRESET`; Node and
MCP both raise PRESET_NOT_FOUND. Use an explicit None check so
Python matches.
Tests added covering structural catalog access, empty-string preset
fail-fast, and cross-lang parity for the empty-string case.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Make the clause library a single-use inclusion checklist instead of a duplicate stamp tool. A clause is either "In contract" or available to "Add clause": a clause already placed can't be inserted again - clicking its card reveals the existing section, while an available card adds it (click or drag) and then flips to "In contract". Drops the "used N times" surface. This teaches the right model: fields are reusable variables, clauses are governed sections included once. - Add a library-only "Return of Materials" clause carrying a nested Receiving party slot, so insert-with-nested-fields stays demonstrable now that the seeded Permitted Use is "In contract" and no longer insertable. - Recolor fields and clauses to the SuperDoc brand blue (--sd-color-blue-500/600, per brand.md) instead of amber. They render as tinted/outlined pills, so they stay distinct from the solid-blue primary buttons. - Update tests (single-use status badges, add-once-no-duplicate, nested-field on add), the README, and code comments to the single-use + blue model.
…art-tags feat(demo): smart-tags palette for custom SDT fields (SD-3320)
…29-215717 🔄 Sync stable → main
fix: make toc toolbar icon configurable
llm tools presets
|
📖 Docs preview: https://superdoc-merge-main-into-stable-2026-05-30.mintlify.app |
Agent docs auditFound deterministic findings on 1 changed agent-doc item(s).
|
|
I attempted to verify against ECMA-376 via the ecma-spec MCP tools, but the tool calls were not permitted in this session (every call returned a permissions error). I've reviewed against the ECMA-376 WordprocessingML schema from knowledge instead, and the file is small and self-contained enough to assess confidently. Status: PASS This handler ( Everything it touches is legitimate WordprocessingML:
A couple of notes (none are violations):
No non-existent elements/attributes, no missing-required issues in what's read, no incorrect defaults written. One caveat for transparency: because the MCP spec tools were blocked, I could not machine-verify the exact section number cited in the JSDoc ( |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 42c6d5ff9e
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| if ( | ||
| options.textModel === 'visible' && | ||
| node.marks?.some((mark: ProseMirrorMark) => mark.type.name === TrackDeleteMarkName) | ||
| ) { |
There was a problem hiding this comment.
Skip deleted inline leaves in visible text
When textModel: 'visible' is used, this filter only suppresses text nodes with trackDelete marks. Tracked deletions can also mark inline leaf nodes (for example images), and those still flow through the later node.isLeaf branch (tabs are emitted even earlier), so doc.getText() can include placeholders/tabs for content that should be hidden from the visible text model, shifting returned text and offsets whenever a deletion covers non-text inline content.
Useful? React with 👍 / 👎.
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Summary
merge/main-into-stable-2026-05-30fromstablemaininto the candidate branchstableAuto-created by promote-stable workflow.